package com.turing.post.thirdinterface.impl;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.Charset;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import com.turing.post.organization.util.BankManage;
import com.turing.post.thirdinterface.util.ThirdInterfaceApplicationException;
import com.turing.post.thirdinterface.util.ThirdInterfaceRespCode;
import com.turing.post.util.PCPSApplicationException;
import com.turing.post.util.PCPSUtil;

/**
 * 邮储联机
 * @author ZXL
 *
 */
public class PSBCSocketOnline {
	
	/**
	 * 控制Socket连接时间
	 * @param bm
	 * @param br
	 * @return
	 * @throws PCPSApplicationException
	 */
	public PSBCBankRequest PSBCControlConnectTime(final BankManage bm,final PSBCBankResponse br)
			throws PCPSApplicationException{
		final ExecutorService exec = Executors.newFixedThreadPool(1);
		PSBCBankRequest psbcRequest = null;
		Callable<PSBCBankRequest> call = new Callable<PSBCBankRequest>() {   
			public PSBCBankRequest call()  throws PCPSApplicationException {   
				return PSBCAssocTransaction(bm,br);   
			}   
		};
		Future<PSBCBankRequest> future = exec.submit(call);   
		try {
			psbcRequest = future.get(1000 * 60, TimeUnit.MILLISECONDS); //任务处理超时时间设为 30秒 
		} catch (TimeoutException e) {
			 throw new PCPSApplicationException(ThirdInterfaceRespCode.RC_SOCKET, 
	 					"邮储联机超时!");
		} catch (Exception e) {
			 throw new PCPSApplicationException(ThirdInterfaceRespCode.RC_SOCKET, 
	 					"邮储联机异常!");
		}
		 // 关闭线程池   
		exec.shutdown();
		return psbcRequest;
	}
	
	/**
	 * 邮储联机Socket
	 * @param bm
	 * @param br
	 * @return
	 * @throws PCPSApplicationException
	 */
	private PSBCBankRequest PSBCAssocTransaction(BankManage bm, PSBCBankResponse br)
			throws PCPSApplicationException{
		
		//验证参数
		if (bm == null || PCPSUtil.isEmpty(bm.getServiceAddr()) || br == null
				|| br.tradeId == null){
			throw new ThirdInterfaceApplicationException(
					ThirdInterfaceApplicationException.ERRMSG_NULLPOINTER,
					ThirdInterfaceRespCode.RC_ARGS_NULL, "参数为空!");
		}
		Socket socket = null;
		OutputStream netOut = null;
		DataOutputStream socketoutput = null;
		DataInputStream in = null;
		PSBCBankRequest psbcRequest = null;
		//消息长度
		int msgInt = 0;
		byte[] msgLength = new byte[4];
		//消息头
		byte[] msgTitle = new byte[3];
		//交易码
		byte[] transactionCode = new byte[5];
		//消息体
		byte[] msgBody  = null;
		//结束标志
		byte[] endMark = new byte[3];
		//得到银行服务地址
		String serviceAddr = bm.getServiceAddr();
		String[] services = serviceAddr.split(":");
		//验证银行服务地址格式
		if (services == null || services.length < 2 
				|| !PCPSUtil.isNumeric(services[1])){
			throw new ThirdInterfaceApplicationException(
					ThirdInterfaceApplicationException.ERRMSG_NULLPOINTER,
					ThirdInterfaceRespCode.RC_PARAMETER, "服务地址:"+serviceAddr+"格式错误!");
		}
		
        try {
            socket = new Socket(services[0], Integer.parseInt(services[1]));   
            netOut = socket.getOutputStream();
            socketoutput = new DataOutputStream(netOut); 
            in = new DataInputStream(socket.getInputStream());
            byte[] messgeBody  = PSBCBankResponse.checkResponseBusinessType(br);
            //将xml中的UTF-8体会为GBK,再格式化去掉里面的回车
			byte[] messgeBodyFormat = PCPSUtil.replaceBlank(
					new String(messgeBody, Charset.forName(
							PSBCBankXmlHelper.XML_CHARSET_GBK)).
							replaceAll(PSBCBankXmlHelper.XML_CHARSET_UTF, 
									PSBCBankXmlHelper.XML_CHARSET_GBK))
									.getBytes(PSBCBankXmlHelper.XML_CHARSET_GBK);
            if (messgeBody == null){
            	throw new ThirdInterfaceApplicationException(
    					ThirdInterfaceApplicationException.ERRMSG_NULLPOINTER,
    					ThirdInterfaceRespCode.RC_PARAMETER, "无此"+br.tradeId+"业务类型!");
            }
            
            //向服务器端发送消息长度(消息长度不包括消息长度本身)
            socketoutput.write(String.format("%04d", messgeBodyFormat.length+11).getBytes());   
            //向服务器端发送消息头    
            socketoutput.write(PSBCBankXmlHelper.XML_XYJ.getBytes());
            //向服务器端发送交易码  
            socketoutput.write(br.tradeId.getBytes());
            //向服务器端发送消息体
            socketoutput.write(messgeBodyFormat);
            //向服务器端发送结束    
            socketoutput.write(PSBCBankXmlHelper.XML_END.getBytes());
            
            //得到消息长度(消息长度不包括消息长度本身)
            msgInt = in.read(msgLength);
            //验证消息长度格式
            if (msgInt != 4 || !PCPSUtil.isNumeric(new String(msgLength))){
            	throw new ThirdInterfaceApplicationException(
    					ThirdInterfaceApplicationException.ERRMSG_NULLPOINTER,
    					ThirdInterfaceRespCode.RC_PARAMETER, "得到消息长度:"+new String(msgLength)+"格式错误!");
            }
            //得到消息头
            msgInt = in.read(msgTitle);
            //验证消息头格式
            if (msgInt != 3 || !PSBCBankXmlHelper.XML_XYJ.equals(new String(msgTitle))){
            	throw new ThirdInterfaceApplicationException(
    					ThirdInterfaceApplicationException.ERRMSG_NULLPOINTER,
    					ThirdInterfaceRespCode.RC_PARAMETER, "得到消息头:"+new String(msgTitle)+"格式错误!");
            }
            //得到交易码
            msgInt = in.read(transactionCode);
            //验证交易码格式
            if (msgInt != 5){
            	throw new ThirdInterfaceApplicationException(
    					ThirdInterfaceApplicationException.ERRMSG_NULLPOINTER,
    					ThirdInterfaceRespCode.RC_PARAMETER, "得到交易码:"+new String(transactionCode)+"格式错误!");
            }
            //验证请求交易码与得到交易码是否一致
            if (!br.tradeId.equals(new String(transactionCode))){
            	throw new ThirdInterfaceApplicationException(
    					ThirdInterfaceApplicationException.ERRMSG_NULLPOINTER,
    					ThirdInterfaceRespCode.RC_PARAMETER, "得到交易码:"+new String(transactionCode)+",与请求交易码:"+br.tradeId+"不一致!");
            }
            msgBody = new byte[Integer.parseInt(new String(msgLength))-11];
            //得到消息体
            msgInt = in.read(msgBody);
            System.out.println("msgBody"+new String(msgBody));
            //验证消息体
            if (msgBody == null || msgInt <= 0){
            	throw new ThirdInterfaceApplicationException(
    					ThirdInterfaceApplicationException.ERRMSG_NULLPOINTER,
    					ThirdInterfaceRespCode.RC_PARAMETER, "得到消息体为空!");
            }
            //得到结束标志
            msgInt = in.read(endMark);
            //验证结束格式
            if (msgInt != 3 || !PSBCBankXmlHelper.XML_END.equals(new String(endMark))){
            	throw new ThirdInterfaceApplicationException(
    					ThirdInterfaceApplicationException.ERRMSG_NULLPOINTER,
    					ThirdInterfaceRespCode.RC_PARAMETER, "得到结束标志:"+new String(endMark)+"格式错误!");
            }
            psbcRequest = PSBCBankRequest.checkRequestBusinessType(br.tradeId,msgBody);
            socketoutput.close();   
            in.close();  
            socket.close();
            netOut.close();
        } catch (Exception e) {
        	 throw new PCPSApplicationException(ThirdInterfaceRespCode.RC_SOCKET, 
 					"邮储联机异常!");
        } finally {   
            if (socket != null) {   
                try {   
                    socket.close();
                    in.close(); 
                    socketoutput.close();
                } catch (IOException e) {   
                	 throw new PCPSApplicationException(ThirdInterfaceRespCode.RC_SOCKET, 
         					"邮储联机异常!");
                }   
            }   
        }   
		return psbcRequest;
	}
}
